﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.IO;
using System.Threading;

namespace Bonobo.Irc.Tests
{
    [TestClass]
    public class IrcConnectionReceiveBufferTest
    {
        [TestMethod]
        public void RecvBuf_SingleMessage()
        {
            var msg = ParseMessages(":luzr COMMAND arg1 arg2 arg3\r\n", 100).SingleOrDefault();
            Assert.IsNotNull(msg);

            Assert.AreEqual("COMMAND", msg.Command);
            Assert.AreEqual("luzr", msg.Prefix);
            Assert.AreEqual(3, msg.Arguments.Count);
            Assert.AreEqual("arg1", msg.Arguments[0]);
            Assert.AreEqual("arg2", msg.Arguments[1]);
            Assert.AreEqual("arg3", msg.Arguments[2]);
        }

        [TestMethod]
        public void RecvBuf_TwoMessages()
        {
            var msgs = ParseMessages("COMMAND arg1\r\nCOMMAND :arg2\r\n", 100);

            Assert.IsNotNull(msgs);
            Assert.AreEqual(2, msgs.Length);

            Assert.AreEqual("COMMAND", msgs[0].Command);
            Assert.AreEqual(null, msgs[0].Prefix);
            Assert.AreEqual(1, msgs[0].Arguments.Count);
            Assert.AreEqual("arg1", msgs[0].Arguments[0]);

            Assert.AreEqual("COMMAND", msgs[1].Command);
            Assert.AreEqual(null, msgs[1].Prefix);
            Assert.AreEqual(1, msgs[1].Arguments.Count);
            Assert.AreEqual("arg2", msgs[1].Arguments[0]);
        }

        [TestMethod]
        public void RecvBuf_HalfMessage()
        {
            var buffer = new IrcConnectionReceiveBuffer(100);

            Read(buffer, ":prefix COM");
            Read(buffer, "MAND arg1\r\n");

            var msg = buffer.ReadMessages().SingleOrDefault();
            Assert.IsNotNull(msg);
            Assert.AreEqual("prefix", msg.Prefix);
            Assert.AreEqual("COMMAND", msg.Command);
            Assert.AreEqual(1, msg.Arguments.Count);
            Assert.AreEqual("arg1", msg.Arguments[0]);
        }

        private static IrcMessage[] ParseMessages(String str, Int32 bufferSize)
        {
            var buffer = new IrcConnectionReceiveBuffer(bufferSize);

            Read(buffer, str);

            return buffer.ReadMessages().ToArray();
        }

        private static void Read(IrcConnectionReceiveBuffer buffer, String str)
        {
            var syncRoot = new Object();
            var stream = CreateStream(str);

            lock (syncRoot)
            {
                buffer.BeginReadFrom(stream, ar =>
                {
                    buffer.EndReadFrom(stream, ar);

                    lock (syncRoot)
                    {
                        Monitor.Pulse(syncRoot);
                    }
                });

                Monitor.Wait(syncRoot);
            }
        }

        private static Stream CreateStream(String msg)
        {
            return new MemoryStream(IrcProtocol.Encoding.GetBytes(msg));
        }
    }
}
